package utils

import (
	"common/global"
	"context"
	"fmt"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

/* monGoDb相关操作 */

// 根据传入条件进行查询
func MongoGetFind(ctx context.Context, collection *mongo.Collection, searchConditions interface{}) (res *mongo.Cursor, err error) {
	res, err = collection.Find(ctx, searchConditions)
	return res, err
}

// 根据传入条件删除文档
func DelMongoWhereSearchConditions(ctx context.Context, collection *mongo.Collection, searchConditions interface{}) {
	collection.DeleteOne(ctx, searchConditions)
}

// 投影查询，类似select name age from stu where id = ?
func ProjectionQuery(key, value string, collection string, selectKey ...string) (interface{}, error) {
	filter := bson.M{key: value} // 根据条件筛选要更新的文档
	// 投影选项
	d := bson.D{}
	for _, k := range selectKey {
		d = append(d, bson.E{Key: k, Value: nil})
	}
	// 查询文档
	res, err := global.MonGoDatabase.Collection(collection).Find(context.Background(), filter, options.Find().SetProjection(d))
	if err != nil {
		return nil, err
	}
	defer res.Close(global.EmptyCtx)
	var rest interface{}
	if err = res.All(global.EmptyCtx, &rest); err != nil {
		return nil, err
	}
	return rest, nil
}

// 插入文档
func InsertDocument(p interface{}, collection string) error {
	if _, err := global.MonGoDatabase.Collection(collection).InsertOne(global.EmptyCtx, p); err != nil {
		return err
	}
	return nil
}

// 插入多条文档
func InsertMultipleDocuments(p []interface{}, collection string) error {
	if _, err := global.MonGoDatabase.Collection(collection).InsertMany(global.EmptyCtx, p); err != nil {
		return err
	}
	return nil
}

// 更据某个字段的值删除文档
func DeleteDocumentByKeyValue(key, value string, collection string) error {
	fil := bson.M{key: value}
	if _, err := global.MonGoDatabase.Collection(collection).DeleteOne(global.EmptyCtx, fil); err != nil {
		return err
	}
	return nil
}

// 根据传入的参数进行更新单条数据
func UpdateSDocumentByKeyValue(key, value string, p interface{}, collection string) error {
	// 根据条件筛选要更新的文档
	filter := bson.M{key: value}
	update := bson.M{"$set": p}
	// 更新文档
	if _, err := global.MonGoDatabase.Collection(collection).UpdateOne(global.EmptyCtx, filter, update); err != nil {
		return err
	}
	return nil
}

// 修改所有符合条件的数据
func UpdateSAllDocumentByKeyValue(key, value, updateKey, updateValue string, collection string) error {
	// 根据条件筛选要更新的文档
	filter := bson.M{key: value}
	update := bson.M{"$set": bson.M{updateKey: updateValue}}
	// 更新文档
	if _, err := global.MonGoDatabase.Collection(collection).UpdateMany(global.EmptyCtx, filter, update); err != nil {
		return err
	}
	return nil
}

// 条件查询 类似于 select * from tablename where ? = ?
func ConditionalQuery(key, value string, collection string) (interface{}, error) {
	filter := bson.M{key: value} // 根据条件筛选要更新的文档
	var s interface{}
	// 插入文档
	err := global.MonGoDatabase.Collection(collection).FindOne(global.EmptyCtx, filter).Decode(&s)
	if err != nil {
		return nil, err
	}
	return s, err
}

// 分页查询 select * from  tablename limit ?
func PagingQuery(size int64, collection string) (interface{}, error) {
	// 分页选项
	l := options.Find().SetLimit(size)
	filter := bson.M{}
	// 插入文档
	res, err := global.MonGoDatabase.Collection(collection).Find(context.TODO(), filter, l)
	if err != nil {
		return nil, err
	}
	defer res.Close(global.EmptyCtx)
	var result interface{}
	if err = res.All(global.EmptyCtx, &result); err != nil {
		return nil, err
	}
	return result, nil
}

// 跳过指定数量的数据
func OffsetQuery(p int64, collection string) (interface{}, error) {
	// 跳跃选项
	l := options.Find().SetSkip(p)
	filter := bson.M{}
	// 插入文档
	res, err := global.MonGoDatabase.Collection(collection).Find(context.TODO(), filter, l)
	if err != nil {
		return nil, err
	}
	defer res.Close(context.Background())

	var result interface{}
	if err = res.All(context.Background(), &result); err != nil {
		return nil, err
	}
	return result, nil
}

// 对查询结果进行降序排序，入参为1升序，入参-1降序  key 排序的字段
func OrderQuery(key string, p int, collection string) (interface{}, error) {
	// 排序选项
	s := options.Find().SetSort(bson.D{{key, p}})
	filter := bson.M{}
	// 3.插入文档
	res, err := global.MonGoDatabase.Collection(collection).Find(context.TODO(), filter, s)
	if err != nil {
		return nil, err
	}
	defer res.Close(context.Background())
	var result interface{}
	if err = res.All(context.Background(), &result); err != nil {
		return nil, err
	}
	return result, nil
}

// 模糊查询 select * from stu where name like %?%
func LikeQuery(key, p string, collection string) (interface{}, error) {
	filter1 := bson.M{
		key: bson.M{
			"$regex": fmt.Sprintf("^%s", p), //name like ?%
		},
	}
	// 查询
	res, err := global.MonGoDatabase.Collection(collection).Find(context.TODO(), filter1)
	if err != nil {
		return nil, err
	}
	defer res.Close(context.Background())
	var result interface{}
	if err = res.All(context.Background(), &result); err != nil {
		return nil, err
	}
	return result, nil
}

// 比较查询 select * from stu where age > ?
func ComparisonQuery(key string, p int, collection string) (interface{}, error) {
	// 过滤条件
	filter := bson.M{
		key: bson.M{
			"$gt": p, // age > p
			// $lt <
			// $gte >=
			// $lte <=
			// $ne !=
		},
	}
	// 查询
	res, err := global.MonGoDatabase.Collection(collection).Find(context.TODO(), filter)
	if err != nil {
		return nil, err
	}
	defer res.Close(context.Background())
	var result interface{}
	if err = res.All(context.Background(), &result); err != nil {
		return nil, err
	}
	return result, nil
}

// 包含查询 select * from tablename where ? in [? ...]
func InclusionQuery(key string, value []string, collection string) (interface{}, error) {
	// 过滤条件
	filter := bson.M{
		key: bson.M{
			"$in": value, // age in [s, e]
			// "$nin": []int{s, e}, // age not in [s, e]
		},
	}
	// 查询
	res, err := global.MonGoDatabase.Collection(collection).Find(context.TODO(), filter)
	if err != nil {
		return nil, err
	}
	defer res.Close(context.Background())
	var result interface{}
	if err = res.All(context.Background(), &result); err != nil {
		return nil, err
	}
	return result, nil
}

// 获取聊天消息

//此处发送给他人 一起发送
/*//连接
func InitMonGoDb() {
	cf := Config.Mongodb
	clientOptions := options.Client().ApplyURI(fmt.Sprintf("mongodb://%s:%d", cf.Hort, cf.Port))
	clientOptions.SetAuth(options.Credential{
		Username: cf.User,
		Password: cf.Passwd,
	})
	ctx, cancel := context.WithTimeout(global.EmptyCtx, 10*time.Second)
	defer cancel()
	var err error
	global.MonGoDbClient, err = mongo.Connect(ctx, clientOptions)
	if err != nil {
		panic(err)
	}
	err = global.MonGoDbClient.Ping(ctx, nil)
	if err != nil {
		panic(err)
	}
	global.Coll = global.MonGoDbClient.Database(cf.Database).Collection(cf.Collection)
	fmt.Println("init MonGODb success")
}*/
